package org.zoomdev.zoom.common.res;

import org.zoomdev.zoom.common.Destroyable;
import org.zoomdev.zoom.common.filter.Filter;
import org.zoomdev.zoom.common.utils.Visitor;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 资源扫描器 用于在项目启动的时候扫描所有资源 1、扫描所有class并记录 2、扫描jar内部class并记录 3、扫描其他类型文件，并记录
 * <p>
 * 方便查找
 * <p>
 * findFile("*.xml"); findFile("*.properties"); findClass("*.controllers.*");
 * <p>
 * 目前这个版本只支持*,不支持**,也就是*就匹配了模糊路径
 * <p>
 * 那么 *.controllers.* 会匹配到 如 com.test.controllers.aaa.Test 如
 * com.test.controllers.aaa.bbb.Test
 * <p>
 * <p>
 * Q:比如两个jar都有app.properties,怎么区分呢？ 那么这个时候会搜索出来两个结果，根据返回结果的file来判断吧
 *
 * @author jzoom
 */
public interface ResScanner extends Destroyable {
    Filter<File> getJarFilter();

    void setFilter(String scanFilter);

    void scan() throws IOException;

    void scan(ClassLoader classLoader) throws IOException;

    void scan(InputStream is, ClassLoader classLoader) throws IOException;


    void scan(ClassLoader classLoader, Filter<File> jarFilter) throws IOException;

    Res getFile(String name);


    ClassRes getClass(String className);

    List<Res> findFile(Filter<Res> filter);

    List<Res> findFile(String pattern);

    List<ClassRes> findClass(String pattern);

    List<ClassRes> findClass(Filter<String> pattern);

    void visitClass(Visitor<ClassRes> visitor);

    /**
     * 为了将来可能的扩展，这里将Class、jar、文件进行抽象
     * 不过我觉得没有什么必要，考虑砍掉。
     */
    interface Res {
        /**
         * 获取实际文件
         *
         * @return
         */
        File getFile();

        /**
         * 获取名字,对于class，那么就是类名称
         *
         * @return
         */
        String getName();

        /**
         * 获取inputStream,用完要关掉
         *
         * @return
         */
        InputStream getInputStream() throws IOException;


        byte[] getBytes() throws IOException;


    }

    interface FileRes extends Res {

    }

    interface ClassRes extends FileRes {
        Class<?> getType();

        Field[] getFields();

        Method[] getPubMethods();
    }
}
